package cn.mengfly.testnrz.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * Jedis 连接池创建构造器
 *
 * @author Mengfly
 */
public class JedisPoolBuilder {

    private static final int MAX_IDLE = 50;
    private static final int MAX_TOTAL = 50;

    private static JedisPool pool = null;

    static {
        buildPool();
        hotPool();
    }

    private static JedisPool buildPool() {
        if (pool == null) {
            long startTime = System.currentTimeMillis();
            JedisPoolConfig config = new JedisPoolConfig();
            // 资源池中的最大连接数，默认值为8
            config.setMaxTotal(MAX_TOTAL);
            // 资源池中允许最大空闲连接数，默认值为8
            config.setMaxIdle(MAX_IDLE);
            // 资源池确保最小空闲连接数，默认值为0,如果JedisPool开启了空闲连接的有效监测，那么在某个空闲连接被判定无效后
            // 如果连接的数量小于这个数量，那么就新建连接，保证空闲连接的数量
            config.setMinIdle(0);
            // 资源用尽后，调用者是否等待
            config.setBlockWhenExhausted(true);
            // 在blockWhenExhausted设置为true的时候才起作用，是指最大等待时间，默认为-1，表示永不超时，不建议使用默认值
            config.setMaxWaitMillis(-1);
            // 向资源池借用连接是，是否做有效性检测，默认值为false
            // 设置为true的话可以保证获取到的每个连接都是可用的
            // 但是监测意味着要发送ping命令去校验，所以业务量小的场景下建议设置为true，业务量大的话建议设置为false
            config.setTestOnBorrow(true);
            // 向资源池归还连接时是否做有效性检测，默认为false
            // 使用场景和testOnBorrow类似
            config.setTestOnReturn(true);
            // 如果为true（默认），会有一个专门的线程对空闲的连接进行有效性的检测扫描，移除无效连接
            // 要想这个配置生效，还需要配置timeBetweenEvictionRunsMillis > 0
            config.setTestWhileIdle(true);
            // 空闲扫描的间隔时间，默认为30000
            config.setTimeBetweenEvictionRunsMillis(30000);
            // 用于一个连接处于空闲时间多久才会进入是否有效的检测
            // 这个参数要生效同样需要设置 timeBetweenEvictionRunsMillis > 0
            config.setMinEvictableIdleTimeMillis(60000);
            // 空闲检测线程每次最多扫描的Jedis连接数，默认为-1，标识全部扫描
            config.setNumTestsPerEvictionRun(-1);
            // 是否开启jmx监控，默认为true，建议开启
            config.setJmxEnabled(true);

            pool = new JedisPool(config, "127.0.0.1", 6379, 10000);
            long end = System.currentTimeMillis();
            System.out.println("build pool 毫秒数：" + (end - startTime));
        }
        return pool;
    }

    /**
     * 线程池预热
     * 因为新创建的连接池里面其实是没有连接的，所以使用的时候在获取就会有一定的时间开销，因此提前预热
     */
    public static void hotPool() {
        long start = System.currentTimeMillis();

        List<Jedis> minIdleJedisList = new ArrayList<>(MAX_IDLE);
        Jedis jedis = null;
        for (int i = 0; i < MAX_IDLE; i++) {
            try {
                jedis = pool.getResource();
                minIdleJedisList.add(jedis);
                jedis.ping();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        for (int i = 0; i < MAX_IDLE; i++) {
            try {
                jedis = minIdleJedisList.get(i);
                jedis.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        long end = System.currentTimeMillis();
        System.out.println("hotPool毫秒数：" + (end - start));
    }

    public static Jedis getJedis() {
        return pool.getResource();
    }

}
